home *** CD-ROM | disk | FTP | other *** search
- /*
- * thinw.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /* THINW: program performs kxk thinning on image and yields
- * thinned image whose values are equal to the original
- * line width around that point
- * usage: thinw inimg outimg [-k MASK_SIZE] [-d] [-I] [-L]
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <math.h>
- #include <images.h>
- #include <tiffimage.h> /* tiff file format info */
- extern void print_sos_lic ();
-
- #define DFLTMAXK 3 /* dflt maximum thinning kernel size */
- #define MAXMAXK 21 /* max of the maximum thinning kernel size */
- #define MAXITER 20 /* maximum number of iterations */
- #define MAXDISPLAY 40 /* maximum length of line for display */
-
- #define OFF 0 /* initial and final value of OFF pixels */
- #define ON 255 /* initial value of ON pixels */
- #define ERASEBASE 51 /* OFF (or formerly erased): 0-ERASEBASE */
- #define ANCHORBASE 101 /* ERASED (this iteration): ERASEBASE-ANCHORBASE */
- #define PONBASE 152 /* ANCHOR (this iteration): ANCHORBASE-PONBASE */
- /* PON (final width value): PONBASE-ON */
-
-
- long ksize (unsigned char **, struct point, long, long, long);
- long getring (unsigned char **, struct point, long, long, long, unsigned char *);
- long sqron (unsigned char **, long, long, long);
- long thinring (unsigned char *, long, long *);
- int width (unsigned char *k, long);
- long chkconnect (unsigned char *, long);
- int anchor (unsigned char *, long);
- int erasesqr (unsigned char **, long, long, unsigned char *, long, int, long *);
- long usage (short);
- long input (int, char **, long *, long *, long *);
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- Image *imgIO; /* input/output image pointer */
- long maxK, /* max. sidelength of thinning kernel */
- k, /* sidelength of current thinning kernel */
- kM1, /* k - 1 */
- change[MAXMAXK], /* no. erasures for each mask size */
- nIter, /* no. iterations */
- x, y, /* image coordinates */
- nChange, /* no. thinning operations on iteration */
- dFlag, /* display results after each iter if =1 */
- invertFlag; /* invert input image before processing */
- long nONs, /* total ONs in original image */
- nErased; /* cumulative no. ERASED in image */
- char c;
- long temp;
- long permOn; /* permanent ON flag set to 1 if so */
- unsigned char **image; /* input/output image */
- struct point imgSize; /* image size */
- unsigned char *ring; /* ring of pixels on perimeter of kxk sqr */
-
- /* user input */
- if (input (argc, argv, &maxK, &dFlag, &invertFlag) < 0)
- return (-1);
-
- /* read input file */
- imgIO = ImageIn (argv[1]);
- image = imgIO->img;
- imgSize.x = ImageGetWidth (imgIO);
- imgSize.y = ImageGetHeight (imgIO);
- if (imgSize.y > MAXDISPLAY)
- dFlag = 0;
-
- /* invert image */
- if (invertFlag) {
- for (y = 0; y < imgSize.y; y++)
- for (x = 0; x < imgSize.x; x++)
- image[y][x] = 255 - image[y][x];
- }
-
- if ((ring = (unsigned char *) malloc (4 * (maxK - 1))) == NULL) {
- printf ("not enough memory -- sorry");
- return (-1);
- }
-
- /* zero image borders */
- for (y = 0; y < imgSize.y; y++)
- image[y][0] = image[y][imgSize.x - 1] = OFF;
- for (x = 0; x < imgSize.x; x++)
- image[0][x] = image[imgSize.y - 1][x] = OFF;
-
- for (k = 0; k < MAXMAXK; k++)
- change[k] = 0;
-
- /* iteratively convolve through image until thinned */
-
- nONs = nErased = 0;
- for (nIter = 0, nChange = 1; (nChange > 0) && nIter <= MAXITER; nIter++) {
- nChange = 0;
- for (y = 1; y < imgSize.y - 1; y++) {
- for (x = 1; x < imgSize.x - 1; x++) {
- permOn = 0;
- k = ksize (image, imgSize, x, y, maxK);
- if (nIter == 0 && k >= 3)
- nONs++;
- kM1 = (k > 3) ? k - 1 : 3;
- while (k >= kM1) {
- if (sqron (image, x, y, k) == 0)
- break;
- if (getring (image, imgSize, x, y, k, ring) == 1)
- break;
- if (thinring (ring, k, &permOn) == 1) {
- if (chkconnect (ring, k) == 1) {
- nChange++;
- (change[k])++;
- erasesqr (image, x, y, ring, k, anchor (ring, k), &nErased);
- break;
- }
- }
- --k;
- }
- if (permOn != 0)
- image[y][x] = (unsigned char) permOn;
- }
- }
- printf ("%d interations: nChange = %7d\n", nIter + 1, nChange);
- printf (" 3: %d, 4: %d, 5: %d, 6: %d, 7: %d\n\n",
- change[3], change[4], change[5], change[6], change[7]);
- for (y = 0; y < imgSize.y; y++) {
- for (x = 0; x < imgSize.x; x++) {
- if (image[y][x] >= ERASEBASE && image[y][x] < ANCHORBASE)
- image[y][x] = image[y][x] - ERASEBASE;
- else if (image[y][x] >= ANCHORBASE && image[y][x] < PONBASE)
- image[y][x] = image[y][x] - ANCHORBASE;
- }
- }
- if (dFlag == 1) {
- for (y = 0; y < imgSize.y; y++) {
- for (x = 0; x < imgSize.x; x++) {
- if (image[y][x] == OFF)
- printf (" ");
- else if (image[y][x] == ON)
- printf ("X ");
- else if (image[y][x] >= PONBASE) {
- temp = (long) image[y][x] - PONBASE;
- if (temp < 10)
- printf ("%1d ", temp);
- else
- printf ("%1d", temp);
- }
- else {
- temp = (long) image[y][x];
- if (temp < 10)
- printf ("%1d ", temp);
- else
- printf ("%1d", temp);
- }
- }
- printf ("\n");
- }
- printf ("Enter <CR> for next iteration.\n");
- scanf ("%c", &c);
- }
- }
- if (dFlag == 1) {
- for (y = 0; y < imgSize.y; y++) {
- for (x = 0; x < imgSize.x; x++) {
- if (image[y][x] == OFF)
- printf (" ");
- else if (image[y][x] == ON)
- printf ("X ");
- else if (image[y][x] >= PONBASE) {
- temp = (long) image[y][x] - PONBASE;
- if (temp < 10)
- printf ("%1d ", temp);
- else
- printf ("%1d", temp);
- }
- else {
- printf ("- ");
- }
- }
- printf ("\n");
- }
- }
- if (nONs == 0)
- printf ("empty image\n");
- else
- printf ("nONs = %d, nErased = %d (%d%%)\n", nONs, nErased,
- (nErased * 100) / nONs);
- if (nIter >= MAXITER && nChange != 0)
- printf ("Nuts -- maximum iterations reached\n");
- for (y = 1; y < imgSize.y - 1; y++)
- for (x = 1; x < imgSize.x - 1; x++)
- image[y][x] = (image[y][x] < PONBASE) ? OFF : ON;
-
- /* un-invert image */
- if (invertFlag) {
- for (y = 0; y < imgSize.y; y++)
- for (x = 0; x < imgSize.x; x++)
- image[y][x] = 255 - image[y][x];
- }
-
- ImageOut (argv[2], imgIO);
-
- return (0);
- }
-
-
- /* KSIZE: function determines k, where kxk is largest square
- * around (x,y) which contains all ON or ERASED
- * usage: k = ksize (image, imgSize, x, y, maxK)
- */
-
- long
- ksize (image, imgSize, x, y, maxK)
- unsigned char **image; /* input/output image */
- struct point imgSize; /* image size */
- long x, y, /* image coordinates */
- maxK; /* maximum k value */
- {
- long k, /* mask size */
- upHalf, downHalf, /* half of mask below and above center */
- xStart, xEnd, /* x- start and end of square */
- yStart, yEnd, /* y- start and end of square */
- xMask, yMask; /* x,y mask coordinates */
-
- if (image[y][x] < ERASEBASE)
- return (0);
-
- for (k = 4; k <= maxK; k++) {
- if (k % 2 == 1)
- downHalf = upHalf = (k - 3) / 2;
- else {
- upHalf = (k - 2) / 2;
- downHalf = (k - 4) / 2;
- }
- xStart = x - downHalf;
- xEnd = x + upHalf;
- yStart = y - downHalf;
- yEnd = y + upHalf;
- for (yMask = yStart; yMask <= yEnd; yMask++)
- for (xMask = xStart; xMask <= xEnd; xMask++)
- if (image[yMask][xMask] < ERASEBASE)
- return (k - 1);
- }
- return (maxK);
- }
-
-
-
- /* GETRING: function gets ring of pixels on perimeter of k-size square
- * usage: allOnes = getring (image, imgSize, x, y, k, ring)
- * If ring includes only ON pixels, function returns 1,
- * otherwise 0.
- */
-
- long
- getring (image, imgSize, x, y, k, ring)
- unsigned char **image; /* input/output image */
- struct point imgSize; /* image size */
- long x, y, /* image coordinages */
- k; /* square sidelength of ring */
- unsigned char *ring; /* ring of pixels on perimeter of kxk sqr */
- {
- long upHalf, downHalf, /* half of mask below and above center */
- xStart, xEnd, /* x- start and end of square */
- yStart, yEnd, /* y- start and end of square */
- i, allOnes; /* =1 if all ones in ring; 0 otherwise */
-
- if (k % 2 == 1)
- downHalf = upHalf = (k - 1) / 2;
- else {
- upHalf = k / 2;
- downHalf = (k - 2) / 2;
- }
- xStart = x - downHalf;
- xEnd = x + upHalf;
- yStart = y - downHalf;
- yEnd = y + upHalf;
-
- allOnes = 1;
- i = 0;
- for (x = xStart, y = yStart; x <= xEnd; x++) {
- if (image[y][x] < ERASEBASE)
- allOnes = 0;
- ring[i++] = image[y][x];
- }
- for (y = yStart + 1, x = xEnd; y <= yEnd; y++) {
- if (image[y][x] < ERASEBASE)
- allOnes = 0;
- ring[i++] = image[y][x];
- }
- for (x = xEnd - 1, y = yEnd; x >= xStart; --x) {
- if (image[y][x] < ERASEBASE)
- allOnes = 0;
- ring[i++] = image[y][x];
- }
- for (y = yEnd - 1, x = xStart; y > yStart; --y) {
- if (image[y][x] < ERASEBASE)
- allOnes = 0;
- ring[i++] = image[y][x];
- }
-
- /* if this square is already at border, cannot go to larger square */
- if (xStart <= 0 || yStart <= 0
- || xEnd >= (imgSize.x - 1) || yEnd >= (imgSize.y - 1))
- return (0);
-
- return (allOnes);
- }
-
-
- /* SQRON: function tests pixels in kxk square are already erased or
- * for 3x3 if they can never be erased
- * usage: flag = sqron (image, x, y, k)
- * flag = 0 if cannot erase any pixels in square
- * = 1 if at least one pixel is still ON
- */
-
- long
- sqron (image, x, y, k)
- unsigned char **image; /* input/output image */
- long x, y, /* image coordinages */
- k; /* square sidelength of ring */
- {
- long upHalf, downHalf, /* half of mask below and above center */
- yStart, yEnd, /* bounds of center erase area */
- xStart, xEnd;
-
- /* check for 3x3 */
- if (k == 3) {
- if (image[y][x] == ON)
- return (1);
- else
- return (0);
- }
-
- /* check center square */
- if (k % 2 == 1)
- downHalf = upHalf = (k - 3) / 2;
- else {
- upHalf = (k - 2) / 2;
- downHalf = (k - 4) / 2;
- }
- xStart = x - downHalf;
- xEnd = x + upHalf;
- yStart = y - downHalf;
- yEnd = y + upHalf;
- for (y = yStart; y <= yEnd; y++)
- for (x = xStart; x <= xEnd; x++)
- if (image[y][x] >= PONBASE)
- return (1);
- return (0);
- }
-
-
-
- /* THINRING: function makes decision to thin or not based on CNUM
- * and FNUM in perimeter ring
- * usage: flag = thinring (ring, k, &permOn)
- * Flag = 1 if thinning conditions met, 0 otherwise.
- */
-
- long
- thinring (ring, k, permOn)
- unsigned char *ring; /* ring of pixels on perimeter of kxk sqr */
- long k; /* square sidelength of ring */
- long *permOn; /* permanent-ON width value */
- {
- long nRing, /* no. pixels in ring */
- cNum, /* connectivity number */
- fNum, /* no. 1s on ring */
- i, n, m;
- long nOff, /* current run of OFF in ring */
- phi0, /* maximum run of OFF in ring */
- nFirstRun; /* no OFF from ring[0] */
- long lower, upper; /* adjacent ring elements for cNum calc */
-
- nRing = 4 * k - 4;
-
- /* calculate FNUM */
- for (i = 0, fNum = 0; i < nRing; i++)
- if (ring[i] >= ERASEBASE)
- fNum++;
-
- /* calculate 4-connected run of 0s */
- nOff = (ring[0] < ERASEBASE) ? 1 : 0;
- nFirstRun = (nOff == 1) ? 0 : -1;
- for (i = 1, phi0 = 0; i < nRing; i++) {
- if (ring[i] < ERASEBASE)
- nOff++;
- else {
- if (nOff > 0) {
- phi0 = (nOff > phi0) ? nOff : phi0;
- if (nFirstRun == 0)
- nFirstRun = nOff;
- nOff = 0;
- }
- }
- }
- if (nOff > 0) {
- if (nFirstRun > 0)
- nOff += nFirstRun;
- phi0 = (nOff > phi0) ? nOff : phi0;
- }
-
- /* CNUM */
- /* CNUM skipping corners */
- for (i = 2, cNum = 0; i < nRing; i++) {
- lower = (long) ring[i - 1];
- if ((i % (k - 1)) == 0)
- i++; /* skip the corner pixels */
- upper = (long) ring[i];
- if (upper >= ERASEBASE && lower < ERASEBASE)
- cNum++;
- }
- if (ring[1] >= ERASEBASE && ring[nRing - 1] < ERASEBASE)
- cNum++;
- /* CNUM at corners */
- for (n = 1; n < 4; n++) {
- m = n * (k - 1);
- if (ring[m] >= ERASEBASE)
- if (ring[m - 1] < ERASEBASE && ring[m + 1] < ERASEBASE)
- cNum++;
- }
- if (ring[0] >= ERASEBASE && ring[1] < ERASEBASE
- && ring[nRing - 1] < ERASEBASE)
- cNum++;
-
- /* to thin or not to thin */
- if (cNum == 1)
- if (phi0 > (k - 2) && fNum > (k - 2))
- return (1);
-
- /* for 3x3, set flag for perm. ON pixel if connection, end, or cross pt */
- if (k == 3)
- if (cNum > 1 || fNum <= 1 || (cNum == 0 && fNum == 4))
- *permOn = width (ring, nRing) + PONBASE;
-
- return (0);
- }
-
-
- /* WIDTH: function calculates average width from boundary of
- * permanent-ON pixel
- * usage: w = width (ring, nRing);
- * Width calculation is made by first finding minima of
- * each ERASED run. Then the minima are averaged and
- * multiplied by 2 to obtain the width estimate.
- */
-
- #define MAXRUNSERASED 4 /* max. no. runs of erased pix.s (for cross) */
-
- int
- width (ring, nRing)
- unsigned char *ring; /* ring of pixels on perimeter of kxk sqr */
- long nRing; /* no. pixels in ring */
- {
- long min[MAXRUNSERASED], /* minimum distance for each erased run */
- nMin, /* no. runs of ERASED */
- width, /* estimated width measurement */
- fNum, /* no. ONs in nbrhood */
- i, j;
-
- /* initialize minimas */
- for (i = 0; i < MAXRUNSERASED; i++)
- min[i] = 255;
-
- /* calculate minima for each run of OFFs in nbrhood */
- for (i = 0, nMin = 0, fNum = 0; i < nRing; i++) {
- if (ring[i] < ERASEBASE) {
- for (j = i; ring[j] < ERASEBASE && j < nRing; j++) {
- if (ring[j] < min[nMin])
- min[nMin] = (long) ring[j];
- else if (ring[j] > PONBASE)
- fNum++;
- }
- nMin++;
- i = j;
- }
- }
- if (ring[0] < ERASEBASE && ring[nRing - 1] < ERASEBASE && fNum > 0) {
- min[0] = (min[0] < min[nMin - 1]) ? min[0] : min[nMin - 1];
- --nMin;
- }
-
- /* calculate average width measurement */
- switch (nMin) {
- case 1:
- width = 2 * min[0] + 1;
- break;
- case 2:
- width = min[0] + min[1] + 1;
- break;
- case 3:
- case 4:
- for (i = 0, width = 0; i < nMin; i++)
- width += min[i];
- width = (long) ((2.0 / nMin) * width + 0.5) + 1;
- break;
- }
- if (width == 0)
- width = 1;
- return (width);
- }
-
-
-
- /* CHKCONNECT: function checks connectivity to see if current erasures
- * combined with past erasures will destroy connectivity
- * usage: flag = chkconnect (ring, k)
- * Function returns flag = 0 if connectivity destroyed,
- * flag = 1 if connectivity retained.
- */
-
- /* if corner or its nbr is ON, then that is value of side, otherwise OFF */
- #define CORNER(ISIDE,ICORNER,ICORNERSIDE,ICORNEROTHER) \
- if (ring[ICORNER] >= PONBASE \
- || ring[ICORNEROTHER] >= ERASEBASE) \
- side[ISIDE] = ON; \
- else side[ISIDE] = OFF
-
- /* for a NW corner, check if corner is anchor point, and if so set to ON */
- #define CORNERNW(ISIDE,ICORNER,ICORNERSIDE,ICORNEROTHER) \
- if (ring[ICORNER] >= ANCHORBASE \
- || ring[ICORNEROTHER] >= ERASEBASE) \
- side[ISIDE] = ON; \
- else side[ISIDE] = OFF
-
- long
- chkconnect (ring, k)
- unsigned char *ring; /* ring of pixels on perimeter of kxk sqr */
- long k; /* square sidelength of ring */
- {
- unsigned char *side; /* array of 8-connected side pixels */
- long nRing, /* no. pixels in ring */
- nSide, /* no. pixels along 8-connected side */
- iSide, /* side array index */
- anON, /* an ON run along side */
- ONandERASE, /* run of ON and n ERASEs */
- N1, /* no. ones in nbrhood */
- i;
-
- nRing = 4 * k - 4;
-
- /* calculate N1 */
- for (i = 0, N1 = 0; i < nRing; i++)
- if (ring[i] >= PONBASE)
- N1++;
- if (N1 == 0)
- return (0);
-
- nSide = k;
- if ((side = (unsigned char *) malloc (nSide)) == NULL) {
- printf ("not enough memory -- sorry");
- return (-1);
- }
-
- /* check connectivity of west side */
- i = 3 * (k - 1);
- CORNER (0, i, i + 1, i - 1);
- for (i = i + 1, iSide = 1; i < nRing; i++, iSide++)
- side[iSide] = ring[i];
- CORNERNW (nSide - 1, 0, nRing - 1, 1);
-
- for (i = 0, anON = 0, ONandERASE = 0; i < nSide; i++) {
- if (side[i] >= PONBASE) {
- if (ONandERASE == 1) {
- free (side);
- return (0);
- }
- else
- anON = 1;
- }
- else if ((side[i] >= ERASEBASE && side[i] < PONBASE)
- && anON == 1)
- ONandERASE = 1;
- else if (side[i] < ERASEBASE)
- anON = ONandERASE = 0; /* off */
- }
-
- /* check connectivity of north side */
- i = k - 1;
- CORNER (0, i, i - 1, i + 1);
- for (i = i - 1, iSide = 1; i >= 0; --i, iSide++)
- side[iSide] = ring[i];
- CORNERNW (nSide - 1, 0, 1, nRing - 1);
-
- for (i = 0, anON = 0, ONandERASE = 0; i < nSide; i++) {
- if (side[i] >= PONBASE) {
- if (ONandERASE == 1) {
- free (side);
- return (0);
- }
- else
- anON = 1;
- }
- else if ((side[i] >= ERASEBASE && side[i] < PONBASE)
- && anON == 1)
- ONandERASE = 1;
- else if (side[i] < ERASEBASE)
- anON = ONandERASE = 0; /* off */
- }
-
- /* check connectivity of east side */
- i = k - 1;
- CORNER (0, i, i + 1, i - 1);
- for (i = i + 1, iSide = 1; iSide < nSide - 1; i++, iSide++)
- side[iSide] = ring[i];
- CORNER (nSide - 1, 2 * (k - 1), 2 * (k - 1) - 1, 2 * (k - 1) + 1);
-
- for (i = 0, anON = 0, ONandERASE = 0; i < nSide; i++) {
- if (side[i] >= PONBASE) {
- if (ONandERASE == 1) {
- free (side);
- return (0);
- }
- else
- anON = 1;
- }
- else if ((side[i] >= ERASEBASE && side[i] < PONBASE)
- && anON == 1)
- ONandERASE = 1;
- else if (side[i] < ERASEBASE)
- anON = ONandERASE = 0; /* off */
- }
- return (1);
- }
-
-
- /* ANCHOR: function returns 1 if core is exposed on NW side
- * usage: anchor (ring, k)
- */
-
- int
- anchor (ring, k)
- unsigned char *ring; /* ring of pixels on perimeter of kxk sqr */
- long k; /* square sidelength of ring */
- {
- long nRing, /* no. pixels in ring */
- i;
-
- nRing = 4 * k - 4;
- for (i = 0; i < k; i++)
- if (ring[i] >= ERASEBASE)
- return (0);
- for (i = 3 * (k - 1) + 1; i < nRing; i++)
- if (ring[i] >= ERASEBASE)
- return (0);
- return (1);
- }
-
-
-
- /* ERASESQR: function erases square contained within square perimeter
- * to minimum width values from the edge
- * usage: erasesqr (image, x, y, ring, k, anchor,
- * &nErased)
- * If the core is an anchor, then the pixels are erased
- * to ERASED + 1, otherwise they are erased to ERASED.
- * For kxk > 3x3 erasure, PON pixels (permanent ON for 3x3)
- * are erased; and if an anchor point (ERASED + 1) can be
- * erased to a non-anchor point by a larger k (I don't know
- * if this can actually happen... I'm pretty sure it cannot
- * and have found on a fingerprint it does not, but have not
- * thought it out yet.) then it is erased to ERASED.
- */
- /* want to erase if ERASED +1, not just ON */
- int
- erasesqr (image, x, y, ring, k, anchor, nErased)
- unsigned char **image; /* input/output image */
- long x, y, /* image coordinages */
- k; /* square sidelength of ring */
- unsigned char *ring; /* ring of pixels on perimeter of kxk sqr */
- int anchor; /* 1 if core is NW pt of NW-SE diag; else 0 */
- long *nErased; /* no. of erased */
- {
- long nRing, /* no. pixels in ring */
- dist; /* minimum dist in ring */
- long upHalf, downHalf, /* half of mask below and above center */
- yStart, yEnd, /* bounds of center erase area */
- xStart, xEnd, i;
- /* find minimum distance value in neighborhood */
- nRing = 4 * k - 4;
- dist = 256;
- for (i = 0; i < nRing; i++)
- if ((long) ring[i] < dist)
- dist = (long) ring[i];
- dist += k - 2;
-
- /* erase for 3x3 */
- if (k == 3) {
- if (image[y][x] == ON) {
- (*nErased)++;
- image[y][x] = (anchor == 0) ? (unsigned char) (ERASEBASE + dist) :
- (unsigned char) (ANCHORBASE + dist);
- }
- }
- /* erase for kxk > 3x3 */
- else {
- if (k % 2 == 1)
- downHalf = upHalf = (k - 3) / 2;
- else {
- upHalf = (k - 2) / 2;
- downHalf = (k - 4) / 2;
- }
- xStart = x - downHalf;
- xEnd = x + upHalf;
- yStart = y - downHalf;
- yEnd = y + upHalf;
- for (y = yStart; y <= yEnd; y++) {
- for (x = xStart; x <= xEnd; x++) {
- if (image[y][x] >= ANCHORBASE) {
- if (image[y][x] >= PONBASE)
- (*nErased)++;
- image[y][x] = (anchor == 0) ? (unsigned char) (ERASEBASE + dist) :
- (unsigned char) (ANCHORBASE + dist);
- }
- }
- }
- }
- return (0);
- }
-
-
-
-
-
- /* USAGE: function gives instructions on usage of program
- * usage: usage (flag)
- * When flag is 1, the long message is given, 0 gives short.
- */
-
- long
- usage (flag)
- short flag; /* flag =1 for long message; =0 for short message */
- {
-
- /* print short usage message or long */
- printf ("USAGE: thinw inimg outimg [-k MASK_SIZE] [-d] [-I] [-L]\n");
- if (flag == 0)
- return (-1);
-
- printf ("\nthinw performs iterative thinning of binary objects in input\n");
- printf ("image to produce skeleton image with values OFF (0) ON (255);\n");
- printf ("skeleton pixel values are widths of the original image lines.\n\n");
- printf ("ARGUMENTS:\n");
- printf (" inimg: input image filename (TIF)\n");
- printf (" outimg: output image filename (TIF)\n\n");
- printf ("OPTIONS:\n");
- printf (" -k MASK_SIZE: window size for kxk mask;(k>=3, default = %d\n", DFLTMAXK);
- printf (" -d: display results of each iteration\n");
- printf (" this only displays for images <= 40x40 to\n");
- printf (" fit on screen.\n");
- printf (" -I: invert input image before processing\n");
- printf (" -L: print Software License for this module\n");
-
- printf (" NOTE: the image output values are the following:\n");
- printf (" -- thinned lines -- width value plus offset of %3d\n", PONBASE);
- printf (" -- off -- %3d\n", OFF);
- printf (" -- on -- %3d\n", ON);
-
- return (-1);
- }
-
-
- /* INPUT: function reads input parameters
- * usage: input (argc, argv, &maxK, &dFlag)
- */
-
- #define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
-
- long
- input (argc, argv, maxK, dFlag, invertFlag)
- int argc;
- char *argv[];
- long *maxK, /* max. sidelength of thinning kernel */
- *dFlag, /* display results after each iter if =1 */
- *invertFlag; /* invert input image before processing */
-
- {
- long n;
-
- if (argc == 1)
- USAGE_EXIT (1);
- if (argc == 2)
- USAGE_EXIT (0);
-
- *maxK = DFLTMAXK;
- *dFlag = 0;
- *invertFlag = 0;
-
- for (n = 3; n < argc; n++) {
- if (strcmp (argv[n], "-k") == 0) {
- if (++n == argc || argv[n][0] == '-')
- USAGE_EXIT (0);
- *maxK = atol (argv[n]);
- }
- else if (strcmp (argv[n], "-d") == 0)
- *dFlag = 1;
- else if (strcmp (argv[n], "-I") == 0)
- *invertFlag = 1;
- else if (strcmp (argv[n], "-L") == 0) {
- print_sos_lic ();
- exit (0);
- }
- else
- USAGE_EXIT (0);
- }
- if (*maxK < 3)
- USAGE_EXIT (1);
- return (0);
- }
-